﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace ErgoLAB.Views.Desgin
{
    /// <summary>
    /// ListViewPathControl.xaml 的交互逻辑
    /// </summary>
    public partial class ListViewPathControl : UserControl
    {
        private double _horizontalSelectedBorder = 8; //水平方向选中边框(单边)
        private double _verticalSelectedBorder = 8;//垂直方向选中边框(单边)
        private double _horizontalPadding = 0;//水平方向距ListView外边框距离(单边)
        private double _verticalPadding = 0;//垂直方向距ListView外边框距离(单边)
        private double _horizontalMargin = 12;//水平方向ListView距离外面容器距离(单边)
        private double _verticalMargin = 12;//垂直方向ListView距离外面容器距离(单边)
        private double _horizontalSpacing = 0;//水平方向2个选中状态的Item的间距(单边)
        private double _verticalSpacing = 0;//垂直方向2个选中状态的Item的间距(单边)
        private double _radius = 12;

        #region Property

        #region PathBrush

        public SolidColorBrush PathBrush
        {
            get { return (SolidColorBrush)GetValue(SelectedBrushProperty); }
            set { SetValue(SelectedBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PathBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SelectedBrushProperty =
            DependencyProperty.Register("PathBrush", typeof(SolidColorBrush), typeof(ListViewPathControl), new PropertyMetadata(new SolidColorBrush(Colors.Black)));

        #endregion

        #region ButtonBrush

        public SolidColorBrush ButtonBrush
        {
            get { return (SolidColorBrush)GetValue(ButtonBrushProperty); }
            set { SetValue(ButtonBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ButtonBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ButtonBrushProperty =
            DependencyProperty.Register("ButtonBrush", typeof(SolidColorBrush), typeof(ListViewPathControl), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(250, 250, 250))));

        #endregion

        #region ItemWidth

        public int ItemWidth
        {
            get { return (int)GetValue(ItemWidthProperty); }
            set { SetValue(ItemWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemWidthProperty =
            DependencyProperty.Register("ItemWidth", typeof(int), typeof(ListViewPathControl), new PropertyMetadata(0, OnItemWidthChanged));

        private static void OnItemWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            LoadPath((ListViewPathControl)d);
        }

        #endregion

        #region ItemHeight

        public int ItemHeight
        {
            get { return (int)GetValue(ItemHeightProperty); }
            set { SetValue(ItemHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemHeightProperty =
            DependencyProperty.Register("ItemHeight", typeof(int), typeof(ListViewPathControl), new PropertyMetadata(OnItemHeightChanged));

        private static void OnItemHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            LoadPath((ListViewPathControl)d);
        }

        #endregion

        #region ItemCount

        public int ItemCount
        {
            get { return (int)GetValue(ItemCountProperty); }
            set { SetValue(ItemCountProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemCount.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemCountProperty =
            DependencyProperty.Register("ItemCount", typeof(int), typeof(ListViewPathControl), new PropertyMetadata(0, OnItemCountChanged));

        private static void OnItemCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            LoadPath((ListViewPathControl)d);
        }

        #endregion

        #region IsAddButton

        public bool IsAddButton
        {
            get { return (bool)GetValue(IsAddButtonProperty); }
            set { SetValue(IsAddButtonProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsAddButton.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsAddButtonProperty =
            DependencyProperty.Register("IsAddButton", typeof(bool), typeof(ListViewPathControl), new PropertyMetadata(false, OnIsAddButtonChanged));

        private static void OnIsAddButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            LoadPath((ListViewPathControl)d);
        }

        #endregion

        #region IsShowPath

        public bool IsShowPath
        {
            get { return (bool)GetValue(IsShowPathProperty); }
            set { SetValue(IsShowPathProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsShowPath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsShowPathProperty =
            DependencyProperty.Register("IsShowPath", typeof(bool), typeof(ListViewPathControl), new PropertyMetadata(true, OnIsShowPathChanged));

        private static void OnIsShowPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            LoadPath((ListViewPathControl)d);
        }

        #endregion

        #region IsShowButton

        public bool IsShowButton
        {
            get { return (bool)GetValue(IsShowButtonProperty); }
            set { SetValue(IsShowButtonProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsShowButton.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsShowButtonProperty =
            DependencyProperty.Register("IsShowButton", typeof(bool), typeof(ListViewPathControl), new PropertyMetadata(false, OnIsShowButtonChanged));

        private static void OnIsShowButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            LoadPath((ListViewPathControl)d);
        }

        #endregion

        #endregion

        #region Event

        #region ButtonClickEvent

        public static readonly RoutedEvent ButtonClickEvent = EventManager.RegisterRoutedEvent("ButtonClick", RoutingStrategy.Bubble,
            typeof(RoutedEventHandler), typeof(ListViewPathControl));

        public event RoutedEventHandler ButtonClick
        {
            add { AddHandler(ButtonClickEvent, value); }
            remove { RemoveHandler(ButtonClickEvent, value); }
        }

        #endregion

        #region ButtonDropEvent

        public static readonly RoutedEvent ButtonDropEvent = EventManager.RegisterRoutedEvent("ButtonDrop", RoutingStrategy.Bubble,
            typeof(RoutedEventHandler), typeof(ListViewPathControl));

        public event RoutedEventHandler ButtonDrop
        {
            add { AddHandler(ButtonDropEvent, value); }
            remove { RemoveHandler(ButtonDropEvent, value); }
        }

        #endregion

        #endregion

        public ListViewPathControl()
        {
            InitializeComponent();
            this.SizeChanged += ListViewPathControl_SizeChanged;
        }

        private void ListViewPathControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            LoadPath(this);
        }

        private static void LoadPath(ListViewPathControl control)
        {
            control.PathCanvas.Children.Clear();

            if (control.ActualWidth == 0 || control.ActualHeight == 0 || control.ItemCount < 0)
                return;

            int count = control.ItemCount;
            if (control.IsAddButton)
                count++;

            double width = control.ActualWidth - control._horizontalMargin * 2;
            double itemActualWidth = control.ItemWidth + control._horizontalSelectedBorder * 2;
            double itemActualHeight = control.ItemHeight + control._verticalSelectedBorder * 2;

            Point startPoint = new Point(-control._horizontalSelectedBorder,
               control._verticalMargin + control._verticalPadding + control._verticalSelectedBorder + control.ItemHeight / 2);
            Point endPoint = new Point();

            int column = (int)Math.Floor(width / itemActualWidth);
            int row = (int)Math.Ceiling((double)count / column);
            // 结束点
            int remainder = count - column * (row - 1);

            if (control.IsShowPath)
            {
                #region 起始点圆

                Ellipse ellipse = new Ellipse();
                ellipse.Fill = control.PathBrush;
                ellipse.Width = control._radius;
                ellipse.Height = control._radius;
                ellipse.SetValue(Canvas.LeftProperty, startPoint.X - ellipse.Width / 2);
                ellipse.SetValue(Canvas.TopProperty, startPoint.Y - ellipse.Height / 2);
                control.PathCanvas.Children.Add(ellipse);

                #endregion

                PathFigure pathFigure = new PathFigure();
                pathFigure.StartPoint = startPoint;

                for (int i = 0; i < row - 1; i++)
                {
                    endPoint.X = control.ActualWidth;
                    endPoint.Y = startPoint.Y + itemActualHeight * i + control._verticalSpacing * i;
                    pathFigure.Segments.Add(new LineSegment(endPoint, true));

                    // 右侧曲线
                    endPoint.Y = endPoint.Y + control._radius * 2;
                    pathFigure.Segments.Add(new ArcSegment(endPoint, new Size(control._radius, control._radius), 180, false,
                        SweepDirection.Clockwise, true));

                    endPoint.X = 0;
                    endPoint.Y = startPoint.Y + itemActualHeight * (i + 1) - control._radius * 2;
                    pathFigure.Segments.Add(new LineSegment(endPoint, false));

                    // 左侧曲线
                    endPoint.Y = endPoint.Y + control._radius * 2;
                    pathFigure.Segments.Add(new ArcSegment(endPoint, new Size(control._radius, control._radius), 180, false,
                        SweepDirection.Counterclockwise, true));
                }

                endPoint.X = control._horizontalPadding + itemActualWidth * remainder + control._horizontalSpacing * (remainder - 1) + control._horizontalSelectedBorder + control._radius;
                endPoint.Y = startPoint.Y + itemActualHeight * (row - 1);
                pathFigure.Segments.Add(new LineSegment(endPoint, true));

                PathGeometry pathGeometry = new PathGeometry();
                pathGeometry.Figures.Add(pathFigure);

                Path path = new Path();
                path.Stroke = control.PathBrush;
                path.StrokeThickness = 4;
                path.Data = pathGeometry;
                control.PathCanvas.Children.Add(path);

                #region  结束位置三角形

                Polygon ploygon = new Polygon();
                ploygon.Stroke = control.PathBrush;
                ploygon.Fill = control.PathBrush;
                ploygon.StrokeThickness = 4;

                endPoint.Y = endPoint.Y - 6;
                ploygon.Points.Add(endPoint);

                endPoint.Y = endPoint.Y + 6;
                endPoint.X = endPoint.X + 8;
                ploygon.Points.Add(endPoint);

                endPoint.X = endPoint.X - 8;
                endPoint.Y = endPoint.Y + 6;
                ploygon.Points.Add(endPoint);

                endPoint.Y = endPoint.Y - 6;
                ploygon.Points.Add(endPoint);
                control.PathCanvas.Children.Add(ploygon);

                #endregion
            }

            if (control.IsShowButton)
            {
                #region Button

                endPoint.X = control._horizontalMargin + control._horizontalPadding + itemActualWidth * (remainder - 1) + control._horizontalSelectedBorder + control._horizontalSpacing * (remainder - 2);
                endPoint.Y = startPoint.Y - control.ItemHeight / 2 + itemActualHeight * (row - 1);

                Button button = new Button();
                button.Width = control.ItemWidth;
                button.Height = control.ItemHeight;
                button.Content = "Drag and drop or click here to add stimuli";
                button.Style = control.Resources["DragButtonStyle"] as Style;
                button.SetValue(Canvas.LeftProperty, endPoint.X);
                button.SetValue(Canvas.TopProperty, endPoint.Y);
                button.Background = control.ButtonBrush;
                button.AllowDrop = true;
                button.Click += Button_Click;
                button.Drop += Button_Drop;
                button.DragEnter += Button_DragEnter;
                control.PathCanvas.Children.Add(button);

                #endregion
            }

            control.Height = startPoint.Y + control.ItemHeight / 2 + itemActualHeight * (row - 1) + control._verticalMargin + control._verticalPadding + control._verticalSelectedBorder;
            control.VerticalAlignment = VerticalAlignment.Top;
        }

        private static void Button_DragEnter(object sender, DragEventArgs e)
        {
            //if (e.Data.GetDataPresent(DataFormats.FileDrop))
            //    e.Effects = DragDropEffects.Link;
            //else
            //    e.Effects = DragDropEffects.None;
        }

        private static void Button_Drop(object sender, DragEventArgs e)
        {
            Array fileNames = ((System.Array)e.Data.GetData(DataFormats.FileDrop));
            if (fileNames == null)
                return;

            RoutedEventArgs args = new RoutedEventArgs(ListViewPathControl.ButtonDropEvent, fileNames);
            ((Button)sender).RaiseEvent(args);
        }

        private static void Button_Click(object sender, RoutedEventArgs e)
        {
            RoutedEventArgs args = new RoutedEventArgs(ListViewPathControl.ButtonClickEvent, e.Source);
            ((Button)sender).RaiseEvent(args);
        }
    }
}
